﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using JellystonePark.Model;
using JellystonePark.Desktop.Data;
using JellystonePark.JellystoneWF.View;

namespace JellystonePark.JellystoneWF
{
    public partial class MainForm : Form
    {
        #region Fields

        private JellystoneModel _game;
        private List<List<PictureBox>>_figures;

        #endregion

        #region Constructor

        public MainForm()
        {
            InitializeComponent();
        }

        #endregion

        #region Main Form event handlers

        /// <summary>
        /// Főablak betöltésének eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form_Load(object sender, EventArgs e)
        {
            try
            {
                using (SetupForm setupForm = new SetupForm())
                {
                    if (setupForm.ShowDialog(this) != DialogResult.OK)
                        throw new Exception("Nem adtál meg nevet!");
                    _game = new JellystoneModel(setupForm.Player.Name, setupForm.Difficulty);

                    if (setupForm.UseDefaultLevels)
                        _game.NewGame(JellystoneFileManager.LoadResource(JellystonePark.Desktop.Data.Resources.DefaultLevels));
                    else
                        LoadExternLevels();
                }
                _game.Initialized += new EventHandler<JellystoneResultEventArgs>(Game_Initialized);
                _game.Advanced += new EventHandler<JellystoneResultEventArgs>(Game_Advanced);
                _game.Stepped += new EventHandler<JellystoneResultEventArgs>(Game_Stepped);
                _game.FigureMoved += new EventHandler<JellystoneVectorEventArgs>(Game_FigureMoved);
                _game.GotBasket += new EventHandler<JellystoneResultEventArgs>(Game_GotBasket);
                _game.LevelOver += new EventHandler<JellystoneResultEventArgs>(Game_LevelOver);
                _game.GameOver += new EventHandler<JellystoneResultEventArgs>(Game_GameOver);
                _figures = new List<List<PictureBox>>();
                _toolStripBaskets.Text = _game.BasketsAll + "/" + _game.BasketsFounded;
                Init();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Hiba!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }
        }

        /// <summary>
        /// Billentyűzet kezelése ablak szinten.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                switch (e.KeyCode)
                {
                    case Keys.Up:
                        _game.StepUp();
                        break;
                    case Keys.Down:
                        _game.StepDown();
                        break;
                    case Keys.Left:
                        _game.StepLeft();
                        break;
                    case Keys.Right:
                        _game.StepRight();
                        break;
                    case Keys.P:
                        _game.Toggle();
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Hiba!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Új játék indításának eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (SetupForm setupForm = new SetupForm())
            {
                _game.Pause();
                if (setupForm.ShowDialog(this) == DialogResult.OK)
                {
                    _game.Player = setupForm.Player;
                    _game.Difficulty = setupForm.Difficulty;
                    if (!setupForm.UseDefaultLevels)
                    {
                        LoadExternLevels();
                    }
                    else
                    {
                        _game.NewGame(JellystoneFileManager.LoadResource(JellystonePark.Desktop.Data.Resources.DefaultLevels));
                        Init();
                    }
                }
                else
                    _game.Continue();
            }
        }

        /// <summary>
        /// Külső pályák betöltésének eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void loadLevelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadExternLevels();
        }

        /// <summary>
        /// Kilépés menüpont kattintás eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// Névjegy gomb kattintás eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>       
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _game.Pause();
            new AboutBox().ShowDialog();
        }

        /// <summary>
        /// Súgó megjelenítése gomb kattintás eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _helpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _game.Pause();
            new HelpForm().ShowDialog();
        }

        #endregion

        #region Game event handlers

        /// <summary>
        /// Modell inicializációjának eseménykezelője, állapotsor inicializálása.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_Initialized(object sender, JellystoneResultEventArgs e)
        {
            _toolStripBaskets.Text = e.BasketsFounded + @"/" + e.BasketsAll;
            _toolStripGameTime.Text = TimeSpan.FromSeconds(e.TimeElapsed).ToString("g");
            _toolStripNoOfSteps.Text = e.Steps.ToString();
        }

        /// <summary>
        /// Játék folyamatának eseménykezelője, időmérő frissítése.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_Advanced(object sender, JellystoneResultEventArgs e)
        {
            Invoke(
                new Action(() =>
                {
                    if (this != null && _game != null)
                    {
                        UpdatePanel();
                        _toolStripGameTime.Text = TimeSpan.FromSeconds(e.TimeElapsed).ToString("g");
                    }
                }));
        }

        /// <summary>
        /// Játék lépés eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_Stepped(object sender, JellystoneResultEventArgs e)
        {
            _toolStripNoOfSteps.Text = e.Steps.ToString();
        }

        /// <summary>
        /// Játék kosár begyűjtés eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_GotBasket(object sender, JellystoneResultEventArgs e)
        {
            _toolStripBaskets.Text = e.BasketsAll.ToString() + "/" + e.BasketsFounded.ToString();
        }

        /// <summary>
        /// Játék vadőr-mozgás eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_FigureMoved(object sender, JellystoneVectorEventArgs e)
        {
            Invoke(new Action(() =>
                {
                    UpdateFigure(e.X, e.Y);
                    UpdateFigure(e.XTo, e.YTo);
                }));
        }

        /// <summary>
        /// Játék szint-vége eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_LevelOver(object sender, JellystoneResultEventArgs e)
        {
            Invoke(new Action(() =>
                {
                    UpdatePanel();
                    if (e.IsWon)
                    {
                        JellystoneFileManager.PlaySound(JellystonePark.Desktop.Data.Resources.WinSound);
                        MessageBox.Show("Nyertél!", (_game.CurrentLevel + 1).ToString() + ". szint", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        _game.NextLevel();
                        Init();
                    }
                    else
                    {
                        JellystoneFileManager.PlaySound(JellystonePark.Desktop.Data.Resources.LoseSound);
                        MessageBox.Show("Vesztettél!", (_game.CurrentLevel + 1).ToString() + ". szint", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        _game.RestartLevel();
                        UpdatePanel();
                    }
                }));
        }

        /// <summary>
        /// Játék vége eseménykezelője.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Game_GameOver(object sender, JellystoneResultEventArgs e)
        {
            if (e.TimeElapsed < Properties.Settings.Default.RecordTime || Properties.Settings.Default.RecordName == "")
            {
                Properties.Settings.Default.RecordName = _game.Player.Name;
                Properties.Settings.Default.RecordSteps = e.Steps;
                Properties.Settings.Default.RecordTime = e.TimeElapsed;
            }
            MessageBox.Show(_game.Player.Name + " eredményei:" + Environment.NewLine +
                "Lépések száma: " + e.Steps.ToString() + Environment.NewLine +
                "Összes játékidő: " + TimeSpan.FromSeconds(e.TimeElapsed).ToString("g"), "A játék véget ért", MessageBoxButtons.OK, MessageBoxIcon.Information);
            Restart();
        }

        #endregion

        #region Private methods

        /// <summary>
        /// A rajztábla és a képeket tartalmazó mátrix inicializálása.
        /// </summary>
        private void Init()
        {
            _game.InitLevel();
            _panel.Controls.Clear();
            _panel.SetBounds(_panel.Location.X, _panel.Location.Y, _game.CurrentTable.SideLength * 50, _game.CurrentTable.SideLength * 50);
            _panel.BackgroundImage = JellystonePark.Desktop.Data.Resources.Background;
            _figures.Clear();
            InitFigures();
            _game.Continue();
        }

        /// <summary>
        /// Megjelenítő mező szinkronizálása a modellben található azonos helyen található mezővel.
        /// </summary>
        /// <param name="x">Oszlopkoordináta</param>
        /// <param name="y">Sorkoordináta</param>
        private void UpdateFigure(int x, int y)
        {
            switch (_game.CurrentTable[x, y])
            {
                case JellystoneTable.JellystoneField.Yogi:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Yogi;
                    break;
                case JellystoneTable.JellystoneField.Basket:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Basket;
                    break;
                case JellystoneTable.JellystoneField.RangerHL:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Ranger;
                    break;
                case JellystoneTable.JellystoneField.RangerVU:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Ranger;
                    break;
                case JellystoneTable.JellystoneField.RangerVD:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Ranger;
                    break;
                case JellystoneTable.JellystoneField.RangerHR:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Ranger;
                    break;
                case JellystoneTable.JellystoneField.Tree:
                    _figures[x][y].Image = JellystonePark.Desktop.Data.Resources.Tree;
                    break;
                default:
                    _figures[x][y].Image = null;
                    break;
            }                
        }

        /// <summary>
        /// A modellben található adatok alapján beállítja figurák helyzetét. Ha nincsenek figurák, akkor létrehozza őket.
        /// </summary>
        private void UpdatePanel()
        {
            for (int i = 0; i < _game.CurrentTable.SideLength; ++i)
                for (int j = 0; j < _game.CurrentTable.SideLength; ++j)
                {
                    UpdateFigure(i, j);
                }
        }

        /// <summary>
        /// Megjelenítő mezők inicializálása.
        /// </summary>
        private void InitFigures()
        {
            _figures.Capacity = _game.CurrentTable.SideLength;
            for (int i = 0; i < _game.CurrentTable.SideLength; ++i)
            {
                _figures.Add(new List<PictureBox>(_game.CurrentTable.SideLength));
                for (int j = 0; j < _game.CurrentTable.SideLength; ++j)
                {
                    _figures[i].Add(new PictureBox());
                    _figures[i][j].BackColor = Color.Transparent;
                    _panel.Controls.Add(_figures[i][j]);
                    _figures[i][j].Height = 50;
                    _figures[i][j].Width = 50;
                    _figures[i][j].Location = new Point(i * 50, j * 50);
                    UpdateFigure(i, j);
                }
            }
            
        }

        /// <summary>
        /// Játék újraindítása.
        /// </summary>
        private void Restart()
        {
            _game.RestartGame();
            Init();
            UpdatePanel();
        }

        /// <summary>
        /// Külső pályacsomag betöltése.
        /// </summary>
        /// <returns>Ha sikerült igaz, különben, hamis.</returns>
        private void LoadExternLevels()
        {
            _game.Pause();
            if (_openLevelFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    _game.NewGame(JellystoneFileManager.LoadFile(_openLevelFileDialog.FileName));
                    if (_figures != null)
                        Init();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Hiba: Külső pályacsomag betöltése", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        #endregion

    }
}
